#include <time.h>
#include <winsock2.h>
#include "MySQL/mysql.h"

#include "CTransportHandler.h"
#include "CDb.h"
#include "CConsole.h"
#include "CGlobal.h"
#include "CNpcPacket.h"
#include "CUtil.h"
#include "CVanaTime.h"
#include "CZoneHandler.h"

std::vector<CTransport> CTransportHandler::transportList;

CTransportHandler::CTransportHandler() {

}

CTransportHandler::~CTransportHandler() {

}

void CTransportHandler::initializeTransports() {
	MYSQL_RES * res;
	MYSQL_ROW row;
	unsigned long size = 0, count, *lengths;
	char query[4096];
	
	//Clear the transport list incase this is a reload
	if((CTransportHandler::transportList.size() > 0)){
		CTransportHandler::transportList.clear();
	}

	//load transport counters
	int transportcnt = 0;
	int airshipcnt = 0;
	int boatcnt = 0;
	int bargecnt = 0;

	//retrieve transports from database
	sprintf(query, "SELECT id, name, type, NPCName, NPCtargId1, NPCtargId2, \
		arrivalTime, arrivalAnimation, arrivalEventId, arrivalEventTime, arrival_charX, arrival_charY, arrival_charZ, arrival_charRot, \
		dockedTime, dockTargId, dockedX, dockedY, dockedZ, dockedRot, dockedZone, \
		departTime, departAnimation, departEventId, departBoundaryId, \
		transportZone, transportEventId FROM `transports`");

	count = (int) strlen(query);

	MYSQL* mysqlConn=CDb::getConn(); //get conn
	mysql_real_query(mysqlConn, query, count);

	res = mysql_store_result(mysqlConn);
	CDb::pushConn(mysqlConn); //release conn

	if(!res)
	{
	} 
	else if(!mysql_num_rows(res))
	{
		mysql_free_result(res);
	} 
	else 
	{
		while(row = mysql_fetch_row(res)){
			lengths = mysql_fetch_lengths(res);
			CTransport trans;
			char type[7];

			trans.m_id = atoi(row[0]);

			memset(trans.m_name, 0 , 30);
			memcpy(trans.m_name, row[1], lengths[1]);

			memset(type, 0 , 7);
			memcpy(type, row[2], lengths[2]);
			if(!memcmp(type, "airship", 7)) {
				trans.m_type = TRANS_AIRSHIP;
				airshipcnt += 1;
			}
			else if(!memcmp(type, "boat", 4)) {
				trans.m_type = TRANS_BOAT;
				boatcnt += 1;
			}
			else if(!memcmp(type, "barge", 5)) {
				trans.m_type = TRANS_BARGE;
				bargecnt += 1;
			}

			trans.m_NPCname = atoi(row[3]);

			trans.m_targId1 = atoi(row[4]);
			trans.m_targId2 = atoi(row[5]);

			trans.m_timeArrive = atoi(row[6]);
			trans.m_arrivalAnim = atoi(row[7]);
			trans.m_arrivalEventId = atoi(row[8]);
			trans.m_timeArriveEvent = atoi(row[9]);

			trans.m_charDockPos.x = (float)atof(row[10]);
			trans.m_charDockPos.y = (float)atof(row[11]);
			trans.m_charDockPos.z = (float)atof(row[12]);
			trans.m_charDockPos.rotation = atoi(row[13]);

			trans.m_timeDock = atoi(row[14]);
			trans.m_dockTargId = atoi(row[15]);
			trans.m_dockPos.x = (float)atof(row[16]);
			trans.m_dockPos.y = (float)atof(row[17]);
			trans.m_dockPos.z = (float)atof(row[18]);
			trans.m_dockPos.rotation = atoi(row[19]);
			trans.m_dockZone = atoi(row[20]);

			trans.m_timeDepart = atoi(row[21]);
			trans.m_departAnim = atoi(row[22]);
			trans.m_departEventId = atoi(row[23]);
			trans.m_dockBoundaryId = atoi(row[24]);

			trans.m_transportZone = atoi(row[25]);
			trans.m_transEventId = atoi(row[26]);

			trans.resetTransNPCs();

			transportList.push_back(trans);
			transportcnt++;

		}

		mysql_free_result(res);
	}

	CConsole::outTime("%i airships, %i boats, %i barges loaded! (%i total transports)",airshipcnt, boatcnt, bargecnt, transportcnt);
}

void CTransportHandler::CTransportTimer() {

	for(unsigned short k = 0; k < transportList.size(); k++) {
		CTransport * trans = &transportList.at(k);

		if((CVanaTime::getInstance()->getDate() % 360) == trans->m_timeArrive) {
			trans->arriveAnim();
		}

		// transport needs to arrive before it can do anything else
		if(trans->isArriving()) {
			if((CVanaTime::getInstance()->getDate() % 360) == trans->m_timeArriveEvent)
				trans->arriveEvent();

			if((CVanaTime::getInstance()->getDate() % 360) == trans->m_timeDock)
				trans->dock();

			if((CVanaTime::getInstance()->getDate() % 360) == trans->m_timeDepart)
				trans->depart();

			// despawn 15 vana minutes after depart
			if((CVanaTime::getInstance()->getDate() % 360) == ((trans->m_timeDepart + 15) % 360))
				trans->despawn();
		}
	}
}

int CTransportHandler::getTransportEvent(CChar * schar) {
	for(unsigned short k = 0; k < transportList.size(); k++) {
		CTransport * trans = &transportList.at(k);
		if((schar->loc.zone == trans->m_dockZone) && (schar->loc.prevzone == trans->m_transportZone))
			return trans->m_arrivalEventId;
	}
	return -1;
}

void CTransportHandler::zoneChar(CChar * schar) {
	for(unsigned int k = 0; k < transportList.size(); k++) {
		CTransport * trans = &transportList.at(k);
		if(schar->onTransport == trans->m_id) {
			schar->zoning = 1;

			if(schar->loc.zone == trans->m_dockZone) {
				position pos;

				// position when zoning onto airship
				if(trans->m_type = TRANS_AIRSHIP) {
					pos.x = 0;
					pos.y = 0;
					pos.z = -20;
					pos.rotation = 0;
				}
				// position for boats/barges unknown at the moment

				schar->loc.p = pos;
				schar->zoneChar(trans->m_transportZone, pos);
			}
			else if(schar->loc.zone == trans->m_transportZone)
				schar->zoneChar(trans->m_dockZone, trans->m_charDockPos);

			break;
		}
	}
}

void CTransportHandler::spawnDock(CChar * schar) {
	for(unsigned int k = 0; k < transportList.size(); k++) {
		CTransport * trans = &transportList.at(k);
		if(schar->onTransport == trans->m_id) {
			if(schar->loc.zone == trans->m_dockZone) {
				CNpc * transportNpc1;
				if(!(transportNpc1 = CZoneHandler::getInstance()->getNpcByTarg(trans->m_targId1, trans->m_dockZone))) {
					return;
				}
				schar->quePacket(CNpcPacket(transportNpc1));
				CNpc * transportNpc2;
				if(!(transportNpc2 = CZoneHandler::getInstance()->getNpcByTarg(trans->m_targId2, trans->m_dockZone))) {
					return;
				}
				schar->quePacket(CNpcPacket(transportNpc2));
				schar->inEvent = true;
				schar->release();
			}
		}
	}
}
